Day26 - AI 對話平台:整合 Temporal 與 AI Agents (上)
Day27 - AI 對話平台:整合 Temporal 與 AI Agents (中)本篇
Day28 - AI 對話平台:整合 Temporal 與 AI Agents (下)
在上一篇文章中,先展開了 Workflow 和 AI Agent 的本質差異,以及為什麼企業級 Workflow 能成為連線兩者的完美橋樑。
本篇將鳥瞰本專案的整體架構,理解一個 AI 對話平台是如何組織的,並為下一篇的深入程式碼實作做好鋪墊。
這是一個具備記帳功能的 AI 對話平台,AI 會自動判斷使用者意圖並路由到對應處理,使用者可以:
chat
):與 AI 進行日常對話weather
):查詢城市天氣資訊ledger_proposal
):透過自然語言收支記帳(「今天買了午餐花了 120 元」)ledger_query
):查詢記帳特定時間範圍的收支(「本月花了多少」)ledger_undo
):撤銷最近一筆記帳系統分為五個主要模組,各司其職:
模組 | 核心職責 | 關鍵技術 |
---|---|---|
WebSocket 通訊層 | 維持長連線、路由訊息、管理 Temporal Client | Handle 快取、冪等性快取 |
Workflow 協調層 | 編排對話流程、處理錯誤 | Entity Pattern、順序處理、ContinueAsNew |
AI 決策層 | 意圖判斷、資料解析、自然語言回覆 | OpenAI Agents SDK、結構化輸出 |
資料持久化層 | 保存會話/訊息、記帳 CRUD | 唯一約束、時間範圍查詢 |
前端狀態管理 | 管理連線、處理訊息收發、本地狀態 | 自定義 Hooks、樂觀更新 |
ws
)- 雙向即時通訊,適合對話場景http
模組┌─────────────────────────────────────────────────────────────────┐
│ Frontend (React) │
│ ┌───────────┐ ┌───────────┐ ┌──────────┐ ┌──────────────┐ │
│ │ useChat │ │ useWebSocket│ │useMessages│ │ useSessions │ │
│ └─────┬─────┘ └──────┬──────┘ └────┬─────┘ └──────┬───────┘ │
│ │ │ │ │ │
│ └────────────────┴──────────────┴──────────────┘ │
│ │ │
└──────────────────────────┼────────────────────────────────────────┘
│ WebSocket (ws://localhost:4000/ws)
│
┌──────────────────────────┼────────────────────────────────────────┐
│ Backend (Node.js) │
│ │ │
│ ┌───────────────────────▼─────────────────────────────┐ │
│ │ WebSocket Server (websocketServer.ts) │ │
│ │ ┌──────────────────────────────────────────────┐ │ │
│ │ │ WebSocket Router (wsRouter.ts) │ │ │
│ │ │ ┌────────────────┐ ┌───────────────────┐ │ │ │
│ │ │ │ handleUserMsg │ │ handleCancel │ │ │ │
│ │ │ └───────┬────────┘ └────────┬──────────┘ │ │ │
│ │ └──────────┼──────────────────────┼─────────────┘ │ │
│ └─────────────┼──────────────────────┼────────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌───────────────────────────────────────────────────┐ │
│ │ Temporal Client │ │
│ │ workflow.executeUpdate('sendMessage') │ │
│ │ workflow.signal('cancel') │ │
│ └─────────────────────┬─────────────────────────────┘ │
└────────────────────────┼───────────────────────────────────────────┘
│ gRPC (localhost:7233)
│
┌────────────────────────▼───────────────────────────────────────────┐
│ Temporal Server (Cluster) │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Workflow Execution Engine │ │
│ │ - Event History Store │ │
│ │ - Task Queue Dispatcher │ │
│ │ - State Machine Manager │ │
│ └──────────────────────────────────────────────────────────┘ │
└────────────────────────┬───────────────────────────────────────────┘
│ Task Queue: "chat-ai"
│
┌────────────────────────▼───────────────────────────────────────────┐
│ Temporal Worker (worker.ts) │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Workflows (workflows.ts) │ │
│ │ ┌────────────────────────────────────────────────────┐ │ │
│ │ │ chatSessionWorkflow │ │ │
│ │ │ - Message Queue Management │ │ │
│ │ │ - Idempotency Control │ │ │
│ │ │ - Error Handling │ │ │
│ │ │ - ContinueAsNew Logic │ │ │
│ │ └────────────────────────────────────────────────────┘ │ │
│ └─────────────────────────┬────────────────────────────────┘ │
│ │ Activity Calls │
│ ┌─────────────────────────▼────────────────────────────────┐ │
│ │ Activities (activities.ts) │ │
│ │ ┌──────────────────┐ ┌──────────────────────────────┐ │ │
│ │ │ AI Activities │ │ DB Activities │ │ │
│ │ │ - decideCapability│ │ - saveMessage │ │ │
│ │ │ - chatReply │ │ - initializeSession │ │ │
│ │ │ - weatherReply │ │ - saveLedger │ │ │
│ │ │ - parseLedger... │ │ - getLedgerEntries │ │ │
│ │ └────────┬──────────┘ └────────┬────────────────────┘ │ │
│ └───────────┼──────────────────────┼───────────────────────┘ │
└──────────────┼──────────────────────┼─────────────────────────────┘
│ │
▼ ▼
┌──────────────────┐ ┌──────────────────┐
│ OpenAI API │ │ SQLite DB │
│ (GPT-4) │ │ - sessions │
│ │ │ - messages │
│ │ │ - ledger_entries│
└──────────────────┘ └──────────────────┘
當使用者發送「今天買了午餐花了120元」,系統會經歷以下流程:
前端 (React)
↓ 1. 產生 requestId,發送 WebSocket 訊息
↓
後端 (WebSocket Router)
↓ 2. 冪等性檢查 → 呼叫 Workflow.executeUpdate()
↓
Temporal Server
↓ 3. 路由到對應的 Workflow 實例
↓
Workflow (Worker)
↓ 4. Update Handler 接收 → 加入 Queue → 主迴圈處理
↓ 5. 呼叫 Activity: decideCapability() → 判斷為 'ledger_proposal'
↓ 6. 呼叫 Activity: parseLedgerProposal() → AI 解析記帳資訊
↓ 7. 呼叫 Activity: saveLedger() → 存入資料庫
↓ 8. 呼叫 Activity: saveMessage() → 存入對話記錄
↓ 9. 回傳結果給 Update Handler
↓
後端 (WebSocket Router)
↓ 10. 快取結果 → 發送 WebSocket 訊息
↓
前端 (React)
↓ 11. 顯示 AI 回覆:「已記帳:午餐 -120.00,時間 2025-10-11 12:00」
關鍵特性:
概念:每個使用者會話(Session)對應一個獨立的長駐 Workflow 實例
實作方式:
sessionId
作為 workflowId
,確保一對一對應優點:
概念:使用 Workflow 內建的記憶體 Queue 順序處理訊息,避免併發問題
實作方式:
condition()
等待 Queue 有內容resolve()
對應的 Promise,回傳結果為什麼不用並行處理?
原則:Workflow 只做協調與決策,所有 I/O 和不確定性操作委派給 Activity
在 Workflow 中可以做:
必須在 Activity 中做:
設計思維:每一層都假設前一層可能失效,逐層防護
層級 | 位置 | 有效期 | 作用 |
---|---|---|---|
Layer 1 | Temporal Server | Workflow 執行期 | Update 的 updateId 提供精確一次語義 |
Layer 2 | Workflow 記憶體 | ContinueAsNew 間隔 | 避免重播時重複呼叫 Activity |
Layer 3 | Backend 記憶體 | 5分鐘 TTL | 減少 Workflow 呼叫壓力,快速回應重複請求 |
Layer 4 | 資料庫 | 永久 | 使用唯一約束(ledgerId/messageId)作為最後防線 |
協同工作:
問題:長駐 Workflow 的事件歷史會無限增長,影響重放效能
解決方案:
continueAsNewSuggested
),主動重新啟動 Workflow優點:
系統採用四層防護策略,從前端到 Activity 逐層處理不同類型的錯誤:
Temporal Web UI 提供完整的監控能力:
應用層日誌 記錄關鍵操作和效能指標,輔助問題排查
系統透過多層快取和狀態管理實現高效運作:
水平擴展(Scale Out):
垂直擴展(Scale Up):
核心優勢:無狀態 Backend + 有狀態 Workflow,實現彈性擴展與自動容錯
本篇概覽了整個專案,展示 Temporal 如何與 AI Agent 協作:AI 負責判斷意圖、解析資料,Temporal 負責保證順序、防止重複、自動重試。Entity Pattern、多層冪等性等設計模式,讓 AI 的智慧決策能被可靠地執行。
下一篇將追蹤完整的記帳流程,看這些設計如何從架構落地到代碼。